<template>
    <div class="es-op-box h-full">
        <ResourceOpPanel>
            <template #left>
                <tag-tree
                    ref="tagTreeRef"
                    :default-expanded-keys="state.defaultExpendKey"
                    :resource-type="TagResourceTypeEnum.EsInstance.value"
                    :tag-path-node-type="NodeTypeTagPath"
                >
                    <template #prefix="{ data }">
                        <span v-if="data.type.value === EsNodeType.Inst">
                            <el-popover :show-after="tooltipTime" placement="right-start" :title="t('common.detail')" trigger="hover" :width="250">
                                <template #reference>
                                    <SvgIcon name="icon es/es-color" :size="18" />
                                </template>
                                <template #default>
                                    <el-descriptions :column="1" size="small">
                                        <el-descriptions-item :label="t('common.name')">
                                            {{ data.params.name }}
                                        </el-descriptions-item>
                                        <el-descriptions-item label="version">
                                            {{ data.params.version }}
                                        </el-descriptions-item>
                                        <el-descriptions-item label="uri">
                                            {{ `${data.params.host}:${data.params.port}` }}
                                        </el-descriptions-item>
                                    </el-descriptions>
                                </template>
                            </el-popover>
                        </span>

                        <SvgIcon v-if="data.type.value === EsNodeType.Indexs" name="Document" />

                        <span v-if="data.type.value === EsNodeType.Index">
                            <el-popover :show-after="tooltipTime" placement="right-start" :title="t('common.detail')" trigger="hover" :width="250">
                                <template #reference>
                                    <SvgIcon name="Document" />
                                </template>
                                <el-descriptions :column="1" size="small">
                                    <el-descriptions-item :label="t('common.name')">
                                        {{ data.params.idxName }}
                                    </el-descriptions-item>
                                    <el-descriptions-item :label="t('es.size')">
                                        {{ data.params.size }}
                                    </el-descriptions-item>
                                    <el-descriptions-item :label="t('es.docs')">
                                        {{ data.params.idx['docs.count'] }}
                                    </el-descriptions-item>
                                </el-descriptions>
                            </el-popover>
                        </span>

                        <SvgIcon v-if="data.type.value === EsNodeType.Dashboard" name="Monitor" />
                        <SvgIcon v-if="data.type.value === EsNodeType.Settings" name="Setting" />
                        <SvgIcon v-if="data.type.value === EsNodeType.Templates" name="DocumentCopy" />
                        <SvgIcon v-if="data.type.value === EsNodeType.BasicSearch || data.type.value === EsNodeType.SeniorSearch" name="Search" />
                    </template>

                    <template #suffix="{ data }">
                        <span v-if="data.type.value === EsNodeType.Index">{{ data.params.size + '/' + (data.params.docs || 0) }}</span>
                    </template>
                </tag-tree>
            </template>

            <template #right>
                <el-card class="h-full" body-class="h-full !p-1 flex flex-col flex-1" ref="esTabDataRef">
                    <div id="es-op-tabs" class="mt-1">
                        <el-tabs @tab-remove="removeDataTab" type="card" class="!h-full w-full" v-model="state.activeName">
                            <template v-for="dt in state.dataTabs" :key="dt.key">
                                <el-tab-pane closable class="!h-full" v-if="dt.tabType === EsNodeType.Index" :label="dt.label" :name="dt.key">
                                    <el-descriptions class="!w-full" :column="20" size="small" border>
                                        <el-descriptions-item label-align="center">
                                            <template #label>
                                                <SvgIcon name="PieChart" />
                                            </template>
                                            {{ dt.params.size }}
                                        </el-descriptions-item>
                                        <el-descriptions-item label-align="center">
                                            <template #label>
                                                <el-space><SvgIcon name="refresh" @click="onRefreshStats(dt)" /> {{ t('es.docs') }}</el-space>
                                            </template>
                                            {{ dt.params.idx['docs.count'] }}
                                        </el-descriptions-item>
                                        <el-descriptions-item :label="t('es.health')" label-align="center">
                                            <el-tag size="small" :type="getHealthTagType(dt.params.idx.health)">{{ dt.params.idx.health }}</el-tag>
                                        </el-descriptions-item>
                                        <el-descriptions-item :label="t('es.status')" label-align="center">
                                            <el-tag size="small" :type="dt.params.idx.status === 'open' ? 'success' : 'danger'">{{
                                                dt.params.idx.status
                                            }}</el-tag>
                                        </el-descriptions-item>
                                    </el-descriptions>
                                    <el-row class="es-op-header">
                                        <el-col :span="20">
                                            <el-space>
                                                <el-tooltip :show-after="tooltipTime" effect="dark" placement="top" :content="t('common.refresh')">
                                                    <el-link @click="onRefreshData(dt)" icon="refresh" underline="never" />
                                                </el-tooltip>

                                                <el-tooltip :show-after="tooltipTime" effect="dark" placement="top" :content="t('es.opSearch')">
                                                    <el-link @click="onBasicSearch(dt)" icon="Search" underline="never" />
                                                </el-tooltip>

                                                <el-tooltip
                                                    :show-after="tooltipTime"
                                                    v-auth="perms.saveData"
                                                    effect="dark"
                                                    placement="top"
                                                    :content="t('common.create')"
                                                >
                                                    <el-link @click="onAddDoc(dt)" icon="plus" underline="never" />
                                                </el-tooltip>
                                                <el-tooltip
                                                    :show-after="tooltipTime"
                                                    v-auth="perms.delData"
                                                    effect="dark"
                                                    placement="top"
                                                    :content="t('common.delete')"
                                                >
                                                    <el-link :disabled="dt.selectKeys.length === 0" @click="onDeleteDocs(dt)" icon="Minus" underline="never" />
                                                </el-tooltip>
                                                <el-tooltip
                                                    :show-after="tooltipTime"
                                                    v-auth="perms.saveData"
                                                    effect="dark"
                                                    placement="top"
                                                    :content="t('common.edit')"
                                                >
                                                    <el-link
                                                        :disabled="dt.selectKeys.length !== 1"
                                                        @click="onEditSelectDoc(dt)"
                                                        icon="EditPen"
                                                        underline="never"
                                                    />
                                                </el-tooltip>
                                                <el-tooltip :show-after="tooltipTime" effect="dark" placement="top" :content="t('es.indexDetail')">
                                                    <el-link @click="onIndexDetail(dt)" icon="InfoFilled" underline="never" />
                                                </el-tooltip>
                                                <el-tooltip :show-after="tooltipTime" effect="dark" placement="top" :content="t('es.page.home')">
                                                    <el-link :disabled="dt.search.from === 0" @click="onFirstPage(dt)" icon="DArrowLeft" underline="never" />
                                                </el-tooltip>
                                                <el-tooltip :show-after="tooltipTime" effect="dark" placement="top" :content="t('es.page.prev')">
                                                    <el-link :disabled="dt.search.from === 0" @click="onPrevPage(dt)" icon="ArrowLeft" underline="never" />
                                                </el-tooltip>

                                                <el-tooltip :show-after="tooltipTime" effect="dark" placement="top" :content="t('es.page.changeSize')">
                                                    <el-dropdown placement="bottom" size="small">
                                                        <el-link underline="never" :style="{ fontSize: '12px' }">
                                                            {{ dt.currentFrom + 1 }} - {{ Math.min(dt.currentFrom + dt.search.size, dt.total) }}</el-link
                                                        >
                                                        <template #dropdown>
                                                            <el-dropdown-menu>
                                                                <el-dropdown-item @click="onChangePageSize(25, dt)">25</el-dropdown-item>
                                                                <el-dropdown-item @click="onChangePageSize(50, dt)">50</el-dropdown-item>
                                                                <el-dropdown-item @click="onChangePageSize(100, dt)">100</el-dropdown-item>
                                                                <el-dropdown-item @click="onChangePageSize(200, dt)">200</el-dropdown-item>
                                                                <el-dropdown-item @click="onChangePageSize(1000, dt)">1000</el-dropdown-item>
                                                            </el-dropdown-menu>
                                                        </template>
                                                    </el-dropdown>
                                                </el-tooltip>
                                                /
                                                <el-tooltip :show-after="tooltipTime" effect="dark" placement="top" :content="t('es.page.total')">
                                                    <el-link
                                                        underline="never"
                                                        @click="onSwitchTrackTotal(dt)"
                                                        :type="dt.search.track_total_hits === true ? 'success' : ''"
                                                        :style="{ fontSize: '12px' }"
                                                    >
                                                        {{ dt.searchRes.hits?.total?.value || 0 }}</el-link
                                                    >
                                                </el-tooltip>
                                                <el-tooltip :show-after="tooltipTime" effect="dark" placement="top" :content="t('es.page.next')">
                                                    <el-link
                                                        :disabled="dt.search.from + dt.search.size >= (dt.total || 0)"
                                                        @click="onNextPage(dt)"
                                                        icon="ArrowRight"
                                                        underline="never"
                                                    />
                                                </el-tooltip>

                                                <!-- <el-tooltip :show-after="tooltipTime" effect="dark" placement="top" :content="t('common.download')">-->
                                                <!--     <el-link @click="onDownload(dt)" icon="Download" underline="never" />-->
                                                <!-- </el-tooltip>-->
                                                <!-- <el-tooltip :show-after="tooltipTime" effect="dark" placement="top" :content="t('common.upload')">-->
                                                <!--     <el-link @click="onUpload(dt)" icon="Upload" underline="never" />-->
                                                <!-- </el-tooltip>-->
                                                <el-tooltip :show-after="tooltipTime" effect="dark" placement="top" :content="t('es.Reindex')">
                                                    <el-link @click="onReindex(dt.params.instId, dt.idxName)" icon="Switch" underline="never" />
                                                </el-tooltip>
                                                <el-tooltip :show-after="tooltipTime" effect="dark" placement="top" :content="t('es.opViewColumns')">
                                                    <el-dropdown placement="bottom" size="small" :max-height="300" :hide-on-click="false" trigger="click">
                                                        <el-link icon="Operation" underline="never" />
                                                        <template #dropdown>
                                                            <el-dropdown-menu class="dropdown-menu">
                                                                <el-dropdown-item>
                                                                    <el-space>
                                                                        <el-checkbox @change="onCheckAllColumns(dt)" v-model="dt.checkAllColumns" />
                                                                        <el-input
                                                                            v-model="dt.columnsFilterText"
                                                                            @input="onFilterColumns(dt)"
                                                                            :placeholder="t('es.filterColumn')"
                                                                            clearable
                                                                            size="small"
                                                                        />
                                                                    </el-space>
                                                                </el-dropdown-item>
                                                                <template v-for="column in dt.columns" :key="column.key">
                                                                    <el-dropdown-item v-if="column._filterd" :command="column.key">
                                                                        <el-checkbox v-model="column._show" @change="onCheckColumnFilter(column)">
                                                                            {{ column.title }}
                                                                        </el-checkbox>
                                                                    </el-dropdown-item>
                                                                </template>
                                                            </el-dropdown-menu>
                                                        </template>
                                                    </el-dropdown>
                                                </el-tooltip>
                                            </el-space>
                                        </el-col>
                                    </el-row>
                                    <div class="es-table-data mt-1" style="height: calc(-208px + 100vh)">
                                        <el-auto-resizer>
                                            <template #default="{ height, width }">
                                                <el-table-v2
                                                    ref="tableRef"
                                                    :row-height="dt.rowHeight"
                                                    :columns="dt.columns"
                                                    :data="dt.datas"
                                                    :width="width"
                                                    :height="height"
                                                    fixed
                                                    :header-height="22"
                                                    class="es-table"
                                                >
                                                    <template #header="{ columns }">
                                                        <div
                                                            v-for="(column, i) in columns"
                                                            :key="i"
                                                            :style="{
                                                                width: `${column.width}px`,
                                                                textAlign: 'center',
                                                                borderRight: 'var(--el-table-border)',
                                                            }"
                                                        >
                                                            <el-checkbox
                                                                :style="{ height: '100%' }"
                                                                v-if="column.key === '_selected'"
                                                                v-model="dt.selectAll"
                                                                @change="onSelectAll(dt)"
                                                                :indeterminate="dt.selectKeys.length > 0 && !dt.selectAll"
                                                            />
                                                            <b v-else> {{ column.title }} </b>
                                                        </div>
                                                    </template>

                                                    <template #cell="{ rowData, column, rowIndex, columnIndex }">
                                                        <div v-if="column.key === '_table_index'" class="table-data-cell">
                                                            <span class="el-text el-text--small is-truncated">
                                                                {{ rowIndex + 1 + dt.currentFrom }}
                                                            </span>
                                                        </div>
                                                        <div v-if="column.key === '_selected'" class="table-data-cell">
                                                            <span class="el-text el-text--small is-truncated">
                                                                <el-checkbox v-model="rowData._selected" @change="onSelectRow(dt, rowData)" />
                                                            </span>
                                                        </div>
                                                        <div
                                                            v-else
                                                            @contextmenu="dataContextmenuClick($event, rowIndex, column, rowData)"
                                                            class="table-data-cell"
                                                        >
                                                            <span v-if="rowData[column.dataKey] === null" style="color: var(--el-color-info-light-5)">
                                                                NULL
                                                            </span>
                                                            <span v-else :title="rowData[column.dataKey]" class="el-text el-text--small is-truncated">
                                                                {{ rowData[column.dataKey] }}
                                                            </span>
                                                        </div>
                                                    </template>

                                                    <template v-if="dt.loading" #overlay>
                                                        <div class="el-loading-mask flex flex-col items-center justify-center">
                                                            <div>
                                                                <SvgIcon class="is-loading" name="loading" color="var(--el-color-primary)" :size="28" />
                                                                <el-text class="ml-1" tag="b"
                                                                    >{{ t('db.execTime') }} - {{ dt.execTime?.toFixed(1) || 0 }}s</el-text
                                                                >
                                                            </div>
                                                            <div v-if="dt.loading && dt.abortSearch" class="!mt-2">
                                                                <el-button @click="dt.abortSearch" type="info" size="small" plain>{{
                                                                    t('common.cancel')
                                                                }}</el-button>
                                                            </div>
                                                        </div>
                                                    </template>
                                                </el-table-v2>
                                            </template>
                                        </el-auto-resizer>
                                    </div>

                                    <es-search
                                        :instId="dt.instId"
                                        :idxName="dt.idxName"
                                        :fields="dt.fields"
                                        v-model:visible="dt.searchDialogVisible"
                                        @search="onEsSearch"
                                    />
                                </el-tab-pane>
                                <el-tab-pane closable class="!h-full" v-if="dt.tabType === EsNodeType.Dashboard" :label="dt.label" :name="dt.key">
                                    <es-dashboard :inst-id="dt.instId" />
                                </el-tab-pane>
                            </template>
                        </el-tabs>
                    </div>
                </el-card>
            </template>
        </ResourceOpPanel>

        <contextmenu :dropdown="state.contextmenu.dropdown" :items="state.contextmenu.items" ref="contextmenuRef" />

        <es-edit-row v-model="docEditDialog" v-model:visible="docEditDialog.visible" @success="onEditRowSuccess" />

        <es-index-detail ref="esIndexDetailRef" />

        <es-add-index
            v-model:visible="addIndexDialog.visible"
            :instId="addIndexDialog.instId"
            :idxNames="addIndexDialog.idxNames"
            @success="onAddIndexSuccess"
        />

        <es-reindex
            :instId="reIndexDialog.instId"
            :idxName="reIndexDialog.idxName"
            :idxNames="reIndexDialog.idxNames"
            v-model:visible="reIndexDialog.visible"
            @success="onReIndexSuccess"
        />

        <es-index-template :inst-id="templateDialog.instId" :version="templateDialog.version" v-model="templateDialog.visible" />

        <div style="text-align: center; margin-top: 10px"></div>
    </div>
</template>

<script lang="tsx" setup>
import { esApi } from './api';
import { defineAsyncComponent, nextTick, reactive, ref, toRefs } from 'vue';

import { TagTreeNode, NodeType } from '../component/tag';
import TagTree from '../component/TagTree.vue';
import { Contextmenu, ContextmenuItem } from '@/components/contextmenu';
import { formatDocSize } from '@/common/utils/format';
import { TagResourceTypeEnum } from '@/common/commonEnum';
import { sleep } from '@/common/utils/loading';
import { useI18n } from 'vue-i18n';
import ResourceOpPanel from '../component/ResourceOpPanel.vue';
import SvgIcon from '@/components/svgIcon/index.vue';
import { copyToClipboard } from '@/common/utils/string';
import { ElCheckbox, ElMessage } from 'element-plus';
import { useI18nConfirm, useI18nDeleteConfirm } from '@/hooks/useI18n';
import { useIntervalFn } from '@vueuse/core';
import Api from '@/common/Api';

const EsAddIndex = defineAsyncComponent(() => import('./component/EsAddIndex.vue'));
const EsDashboard = defineAsyncComponent(() => import('./component/EsDashboard.vue'));
const EsEditRow = defineAsyncComponent(() => import('./component/EsEditRow.vue'));
const EsIndexDetail = defineAsyncComponent(() => import('./component/EsIndexDetail.vue'));
const EsIndexTemplate = defineAsyncComponent(() => import('./component/EsIndexTemplate.vue'));
const EsReindex = defineAsyncComponent(() => import('./component/EsReindex.vue'));
const EsSearch = defineAsyncComponent(() => import('./component/EsSearch.vue'));

const { t } = useI18n();

const perms = {
    saveData: 'es:data:save',
    delData: 'es:data:del',
};

const getDefaultSearch = () => ({ sort: {}, query: { bool: { must: [], should: [], must_not: [] } }, aggs: {}, from: 0, size: 25 });

const tooltipTime = 300;

const state = reactive({
    defaultExpendKey: [] as any,
    tags: [],
    mongoList: [] as any,
    activeName: '', // 当前操作的tab
    dataTabs: {} as any, // 数据tabs
    reloadStatus: false,
    showSysIndex: false,
    contextmenu: { items: [] as any[], dropdown: { x: 0, y: 0 } },
    docEditDialog: {
        instId: '',
        isAdd: true,
        loading: false,
        visible: false,
        doc: '',
        idxName: '',
        _id: '',
    },
    addIndexDialog: {
        instId: '' as any,
        visible: false,
        data: {} as any,
        idxNames: [] as string[],
    },
    reIndexDialog: {
        instId: '' as any,
        idxName: '' as any,
        visible: false,
        idxNames: [] as string[],
    },
    templateDialog: {
        instId: '' as any,
        version: '',
        visible: false,
    },
});

const { docEditDialog, addIndexDialog, reIndexDialog, templateDialog } = toRefs(state);
/**
 * 树节点类型
 */
class EsNodeType {
    static Inst = 1; // 实例
    static Indexs = 2; // 索引管理
    static Index = 21; // 索引管理
    static BasicSearch = 3; // 基础搜索
    static SeniorSearch = 4; // 高级搜索
    static Dashboard = 5; // 数据看板
    static Settings = 6; // 基本设置
    static Templates = 7; // 模板管理
}

const contextmenuRef = ref();
const esTabDataRef = ref();
const esIndexDetailRef = ref();
const tableRef = ref();
const instIndicesMap = new Map();

const getIndicesByInstId = async (instId: any) => {
    if (!instIndicesMap.has(instId)) {
        await refreshIndices(instId);
    }
    return instIndicesMap.get(instId);
};

const refreshIndices = async (instId: any) => {
    let indicesRes = await esApi.proxyReq('get', instId, `/_cat/indices/?h=index,health,status,uuid,pri,rep,docs.count,docs.deleted,store.size,sc,cd`);
    instIndicesMap.set(instId, indicesRes);
};

// tagpath 节点类型
const NodeTypeTagPath = new NodeType(TagTreeNode.TagPath)
    .withContextMenuItems([new ContextmenuItem('refresh', 'common.refresh').withIcon('refresh').withOnClick(async (data: any) => await reloadNode(data.key))])
    .withLoadNodesFunc(async (parentNode: TagTreeNode) => {
        // 加载es实例列表
        const res = await esApi.instances.request({ tagPath: parentNode.key });
        if (!res.total) {
            return [];
        }
        const insts = res.list;
        await sleep(100);
        return insts?.map((x: any) => {
            x.tagPath = parentNode.key;
            return new TagTreeNode(`es.inst.${x.code}`, x.name, NodeTypeInst).withParams(x);
        });
    });

// 加载实例列表
const NodeTypeInst = new NodeType(EsNodeType.Inst)
    .withLoadNodesFunc(async (parentNode: TagTreeNode) => {
        const params = parentNode.params;

        let oiKey = `es.${params.id}.opIndex`;
        let bsKey = `es.${params.id}.opBasicSearch`;
        let ssKey = `es.${params.id}.opSeniorSearch`;
        let dbKey = `es.${params.id}.opDashboard`;
        let stKey = `es.${params.id}.opSettings`;
        let tpKey = `es.${params.id}.optemplates`;

        let nodeParams = { inst: params, instId: params.id };

        return [
            new TagTreeNode(oiKey, t('es.opIndex'), NodeTypeIndexs).withParams(nodeParams),
            // new TagTreeNode(ssKey, t('es.opSeniorSearch'), NodeTypeSeniorSearch).withParams(nodeParams).withIsLeaf(true),
            // new TagTreeNode(dbKey, t('es.opDashboard'), NodeTypeDashboard).withParams(nodeParams).withIsLeaf(true),
            // new TagTreeNode(stKey, t('es.opSettings'), NodeTypeSettings).withParams(nodeParams),
        ];
    })
    .withNodeClickFunc((nodeData: TagTreeNode) => {
        // 添加一个dashboard tab

        const label = `${nodeData.key}.dashboard`;
        state.activeName = label;

        let dataTab = state.dataTabs[label];
        if (dataTab) {
            return;
        }
        dataTab = {
            tabType: EsNodeType.Dashboard,
            params: nodeData.params,
            key: label,
            label: nodeData.label,
            name: label,
            instId: nodeData.params.id,
        };

        state.dataTabs[label] = dataTab;
    });

const NodeTypeIndexs = new NodeType(EsNodeType.Indexs)
    .withContextMenuItems([
        new ContextmenuItem('refresh', 'common.refresh').withIcon('refresh').withOnClick(async (data: any) => onRefreshIndices(data.params.instId, data.key)),
        new ContextmenuItem('addIndex', 'es.contextmenu.index.addIndex').withIcon('plus').withOnClick((data: any) => onAddIndex(data)),
        new ContextmenuItem('showSys', 'es.contextmenu.index.showSys').withIcon('View').withOnClick((data: any) => onShowSysIndex(data)),
        new ContextmenuItem('idxTemplate', 'es.templates').withIcon('DocumentCopy').withOnClick((data: any) => onShowTemplate(data)),
    ])
    .withLoadNodesFunc(async (parentNode: TagTreeNode) => {
        const params = parentNode.params;
        // 展示索引列表，显示索引名，文档总数，
        let idxNodes = [];
        let indices = {} as any;
        let keys = [] as string[];

        // 加载索引列表
        let indicesRes = await getIndicesByInstId(params.instId);
        indicesRes.forEach((x: any) => {
            if (state.showSysIndex) {
                indices[x.index] = x;
                keys.push(x.index);
            } else if (!x.index.startsWith('.') && x.index.indexOf('.') < 0) {
                indices[x.index] = x;
                keys.push(x.index);
            }
        });

        keys = keys.sort();

        for (let idxName of keys) {
            const idx = indices[idxName];
            const key = `es.${params.inst.id}.index.${idxName}`;
            idxNodes.push(
                new TagTreeNode(key, idxName, NodeTypeIndex)
                    .withIsLeaf(true)
                    .withParams({
                        instId: params.instId,
                        idxName,
                        idx,
                        params,
                        key: key,
                        parentKey: parentNode.key,
                        size: idx['store.size'],
                        docs: formatDocSize(idx['docs.count'] || 0, 1),
                    })
                    .withIcon('Document')
            );
        }

        state.showSysIndex = false;
        return idxNodes;
    });

// 索引操作
const NodeTypeIndex = new NodeType(EsNodeType.Index)
    .withContextMenuItems([
        // 右键菜单支持：复制名字、新增别名、迁移索引、关闭、启用、删除、数据浏览、跳转基础查询、跳转高级查询
        new ContextmenuItem('copyName', 'es.contextmenu.index.copyName').withIcon('copyDocument').withOnClick((data: any) => onIdxCopyName(data)),
        new ContextmenuItem('refresh', 'es.contextmenu.index.refresh').withIcon('refresh').withOnClick((data: any) => onRefreshIdx(data)),
        new ContextmenuItem('clearCache', 'es.contextmenu.index.clearCache').withIcon('refresh').withOnClick((data: any) => onClearIdxCache(data)),
        new ContextmenuItem('flush', 'es.contextmenu.index.flush').withIcon('refresh').withOnClick((data: any) => onFlushIdx(data)),
        new ContextmenuItem('Reindex', 'es.Reindex').withIcon('Switch').withOnClick((data: any) => onIdxReindex(data)),
        new ContextmenuItem('Close', 'es.contextmenu.index.Close')
            .withIcon('Close')
            .withOnClick((data: any) => onIdxClose(data))
            .withHideFunc((data: any) => {
                return data.params.idx.status !== 'open';
            }),
        new ContextmenuItem('Open', 'es.contextmenu.index.Open')
            .withIcon('Select')
            .withOnClick((data: any) => onIdxOpen(data))
            .withHideFunc((data: any) => {
                return data.params.idx.status === 'open';
            }),
        new ContextmenuItem('Delete', 'es.contextmenu.index.Delete').withIcon('Delete').withOnClick((data: any) => onIdxDelete(data)),
        new ContextmenuItem('BaseSearch', 'es.contextmenu.index.BaseSearch').withIcon('Search').withOnClick((data: any) => onIdxBaseSearch(data)),
        // new ContextmenuItem('SeniorSearch', 'es.contextmenu.index.SeniorSearch').withIcon('Search').withOnClick((data: any) => onIdxSeniorSearch(data)),
        new ContextmenuItem('IndexDetail', 'es.indexDetail').withIcon('InfoFilled').withOnClick((data: any) => onIndexDetail(data)),
    ])

    .withNodeClickFunc((nodeData: TagTreeNode) => {
        const params = nodeData.params;
        contextmenuRef.value.closeContextmenu();
        loadIndexData(params.params.inst.id, params);
    });

const onRefreshIndices = async (instId: any, key: any) => {
    await refreshIndices(instId);
    await reloadNode(key);
};

const onAddIndex = async (data: any) => {
    // 弹出新增/修改索引窗口
    state.addIndexDialog.data = data;
    state.addIndexDialog.instId = data.params.instId;
    state.addIndexDialog.visible = true;
    let indices = await getIndicesByInstId(data.params.instId);
    state.addIndexDialog.idxNames = indices
        .map((x: any) => x.index)
        .filter((x: any) => x.indexOf('.') < 0)
        .sort();
};

const onAddIndexSuccess = async () => {
    await onRefreshIndices(state.addIndexDialog.data.params.instId, state.addIndexDialog.data.key);
};

const onReIndexSuccess = () => {
    console.log('onReIndexSuccess');
};
const onIdxCopyName = async (data: any) => {
    await copyToClipboard(data.params.idxName);
};
const onRefreshIdx = async (data: any) => {
    await esApi.proxyReq('post', data.params.instId, `/${data.params.idxName}/_refresh`);
    ElMessage.success(t('common.operateSuccess'));
};
const onClearIdxCache = async (data: any) => {
    await useI18nConfirm('es.clearCacheConfirm', { name: data.params.idxName });
    await esApi.proxyReq('post', data.params.instId, `/${data.params.idxName}/_cache/clear`);
    ElMessage.success(t('common.operateSuccess'));
};
const onFlushIdx = async (data: any) => {
    await esApi.proxyReq('post', data.params.instId, `/${data.params.idxName}/_flush`);
    ElMessage.success(t('common.operateSuccess'));
};
const onIdxReindex = async (data: any) => {
    await onReindex(data.params.instId, data.params.idxName);
};
const onIdxClose = async (data: any) => {
    await useI18nConfirm('es.closeIndexConfirm', { name: data.params.idxName });
    await esApi.proxyReq('post', data.params.instId, `/${data.params.idxName}/_close`);
    data.params.idx.status = 'close';
    ElMessage.success(t('common.operateSuccess'));
};
const onIdxOpen = async (data: any) => {
    await useI18nConfirm('es.openIndexConfirm', { name: data.params.idxName });
    await esApi.proxyReq('post', data.params.instId, `/${data.params.idxName}/_open`);
    data.params.idx.status = 'open';
    ElMessage.success(t('common.operateSuccess'));
};
const onIdxDelete = async (data: any) => {
    await useI18nDeleteConfirm(data.params.idxName);
    await esApi.proxyReq('delete', data.params.instId, data.params.idxName);
    ElMessage.success(t('common.deleteSuccess'));
    await onRefreshIndices(data.params.instId, data.params.parentKey);
};
const onIdxBaseSearch = async (data: any) => {
    // 加载表数据
    let params = data.params;
    await loadIndexData(params.params.inst.id, params);
    // 弹出搜索窗口
    await onBasicSearch(getNowDataTab());
};

const loadIndexData = async (instId: any, params: any) => {
    let idxName = params.idxName;
    const label = `es.${instId}.index.${idxName}`;
    state.activeName = label;

    let dataTab = state.dataTabs[label];
    if (dataTab) {
        return;
    }
    dataTab = {
        tabType: EsNodeType.Index,
        params: params,
        key: label,
        label: idxName,
        name: label,
        instId,
        idxName,
        columns: [],
        fields: [],
        datas: [],
        total: [],
        searchRes: {} as any,
        rowHeight: 30,
        selectAll: false,
        selectKeys: [],
        columnsFilterText: '',
        checkAllColumns: true,
        loading: true,
        abortSearch: () => {},
        execTime: 0,
        currentFrom: 25,
        search: getDefaultSearch(),
        searchDialogVisible: false,
    };
    state.dataTabs[label] = dataTab;
    // 延时加载数据，避免卡顿
    setTimeout(fetchIndexData, 300);
};

// 选中的数据， key->rowIndex  value->primaryKeyValue
const selectionRowsMap = ref(new Map<number, any>());
/**
 * 判断当前行是否被选中
 * @param rowIndex
 */
const isSelection = (rowIndex: number): boolean => {
    return selectionRowsMap.value.get(rowIndex);
};

/**
 * 选中指定行
 * @param rowIndex
 * @param rowData
 * @param isMultiple 是否允许多选
 */
const selectionRow = (rowIndex: number, rowData: any, isMultiple = false) => {
    if (isMultiple) {
        // 如果重复点击，则取消改选中数据
        if (selectionRowsMap.value.get(rowIndex)) {
            selectionRowsMap.value.delete(rowIndex);
            return;
        }
    } else {
        selectionRowsMap.value.clear();
    }
    selectionRowsMap.value.set(rowIndex, rowData);
};

const copyCell = new ContextmenuItem('copyCell', 'common.copyCell').withIcon('CopyDocument').withOnClick(async (data: any) => {
    await copyToClipboard(data.rowData[data.column.dataKey]);
});

const copyLineJson = new ContextmenuItem('copyLineJson', 'es.contextmenu.index.copyLineJson').withIcon('CopyDocument').withOnClick(async (data: any) => {
    await copyToClipboard(data.rowData.src);
});

const copySelectLineJson = new ContextmenuItem('copySelectLineJson', 'es.contextmenu.index.copySelectLineJson')
    .withIcon('CopyDocument')
    .withHideFunc(() => {
        let dt = getNowDataTab();
        if (dt) {
            return dt.selectKeys?.length == 0;
        }
        return true;
    })
    .withOnClick(async () => {
        await copyToClipboard(
            JSON.stringify(
                getNowDataTab().selectKeys.map((a: any) => JSON.parse(a.src)),
                null,
                2
            )
        );
    });

const editLineJson = new ContextmenuItem('editLineJson', 'common.edit').withIcon('EditPen').withOnClick(async (data: any) => onEditDoc(data.rowData.src));

const deleteLine = new ContextmenuItem('deleteLine', 'common.delete').withIcon('Delete').withOnClick(async (data: any) => {
    // 二次确认后执行删除
    let ids = [data.rowData._id];
    await useI18nDeleteConfirm(ids.join(', '));
    await doDeleteDoc(ids);
});
const deleteSelectLine = new ContextmenuItem('deleteLine', 'es.contextmenu.index.DeleteSelectLine')
    .withIcon('Delete')
    .withHideFunc(() => {
        return getNowDataTab().selectKeys.length == 0;
    })
    .withOnClick(async () => {
        // 二次确认后执行删除
        let ids = getNowDataTab().selectKeys.map((a: any) => a._id);
        await useI18nDeleteConfirm(ids.join(', '));
        await doDeleteDoc(ids);
    });

const dataContextmenuClick = (event: any, rowIndex: number, column: any, data: any) => {
    event.preventDefault(); // 阻止默认的右击菜单行为
    // 当前行未选中，则单行选中该行
    if (!isSelection(rowIndex)) {
        selectionRow(rowIndex, data);
    }
    const { clientX, clientY } = event;
    state.contextmenu.dropdown.x = clientX;
    state.contextmenu.dropdown.y = clientY;
    state.contextmenu.items = [copyCell, copyLineJson, copySelectLineJson, editLineJson, deleteLine, deleteSelectLine];
    contextmenuRef.value.openContextmenu({ column, rowData: data });
};

const reloadNode = async (nodeKey: string) => {
    state.reloadStatus = true;
    await tagTreeRef.value.reloadNode(nodeKey);
};

const onShowSysIndex = async (data: any) => {
    state.showSysIndex = true;
    await reloadNode(data.key);
};
const onShowTemplate = async (data: any) => {
    state.templateDialog.visible = true;
    state.templateDialog.version = data.params.inst.version;
    state.templateDialog.instId = data.params.instId;
    console.log(state.templateDialog);
};

const tagTreeRef: any = ref(null);

const onChangePageSize = async (size: number, dt: any) => {
    dt.search.size = size;
    dt.search.from = 0;
    await fetchIndexData(); // 改变每页条数
};

const onFirstPage = async (dt: any) => {
    dt.search.from = 0;
    await fetchIndexData(); // 回到首页
};
const onNextPage = async (dt: any) => {
    dt.search.from = dt.search.from + dt.search.size;
    await fetchIndexData(); // 下一页
};

const onPrevPage = async (dt: any) => {
    dt.search.from = Math.max(0, dt.search.from - dt.search.size);
    await fetchIndexData(); // 上一页
};

const refreshIndex = async () => {
    const dataTab = getNowDataTab();
    await esApi.proxyReq('post', dataTab.instId, `/${dataTab.idxName}/_refresh`);
};

const onEditRowSuccess = async () => {
    await refreshIndex();
    await fetchIndexData(); // 编辑完成后刷新索引数据
};

// 获取索引数据
const fetchIndexData = async () => {
    const dt = getNowDataTab();

    dt.execTime = 0;
    // loading
    const { pause, resume } = useIntervalFn(() => {
        dt.execTime += 0.1;
    }, 100);
    resume();
    dt.loading = true;

    // 清空选中
    dt.selectAll = false;
    dt.selectKeys = [];

    let api = Api.newPost(`/es/instance/proxy/${dt.instId}/${dt.idxName}/_search`);

    const { execute: execSearch, data: searchRes, abort: abortSearch } = api.useApi<any>(dt.search, { esProxyReq: true });
    dt.abortSearch = () => {
        abortSearch();
        dt.loading = false;
        pause();
    };
    // 获取数据
    await execSearch();
    dt.searchRes = searchRes;
    let error = searchRes.value.error || (searchRes.value.failures && searchRes.value.failures.length > 0 && searchRes.value.failures[0]);
    if (error) {
        dt.loading = false;
        pause();
        return await esApi.alertError(error, t('es.execError'));
    }

    // 搜集字段信息
    let fieldMap = {} as any;
    fieldMap['_id'] = { width: 50 };

    // 处理数据
    dt.datas = dt.searchRes.hits.hits.map((a: any) => {
        let src = JSON.parse(JSON.stringify(a._source));
        src._id = a._id;
        let source = a._source;
        source._id = a._id;
        source._score = a._score;
        fieldMap['_score'] = { width: 40 };
        // 如果字段不是字符串或数字，则转换为json字符串
        for (let k in source) {
            if (typeof source[k] != 'string' && typeof source[k] != 'number' && source[k] !== null && typeof source[k] != 'boolean') {
                source[k] = JSON.stringify(source[k]);
            }
            // 表格长度为值长度的十倍px，最小50px，最大220px
            let column = fieldMap[k] || { width: 50 };
            try {
                let valLength = source[k] ? Math.max(source[k].length, k.length) : k.length;
                column.width = Math.max(Math.max(Math.min(220, (valLength || 10) * 10), 50), column.width);
            } catch (e) {
                console.log(e);
                column.width = 50;
            }
            fieldMap[k] = column;
        }
        // 缓存原始数据
        source.src = JSON.stringify(src, null, 2);
        source._selected = false;
        return source;
    });

    dt.total = dt.searchRes.hits?.total.value || 0;

    if (dt.datas.length > 0) {
        let keys = Object.keys(fieldMap).sort();
        dt.fields = keys.filter((k) => k != '_score');
        dt.columns = keys.map((k) => ({ title: k, width: fieldMap[k].width, key: k, dataKey: k, class: 'es-table-column', _filterd: true, _show: true }));
        dt.columns.unshift({
            title: '#',
            width: 50,
            key: '_table_index',
            class: 'es-table-column',
            align: 'center',
            _filterd: false,
        });

        dt.columns.unshift({
            title: 'checkbox',
            width: 30,
            key: '_selected',
            class: 'es-table-column',
            align: 'center',
            _filterd: false,
        });
    }
    pause();
    dt.loading = false;
    dt.currentFrom = dt.search.from;
};

const onRefreshData = async (dt: any) => {
    // dt.search = getDefaultSearch();
    await fetchIndexData(); // 刷新到首页
};

const onAddDoc = async (dt: any) => {
    state.docEditDialog.isAdd = true;
    state.docEditDialog.instId = dt.instId;
    state.docEditDialog._id = '';
    state.docEditDialog.idxName = dt.idxName;
    state.docEditDialog.visible = true;
};

const onEditDoc = async (src: any) => {
    state.docEditDialog.isAdd = false;
    state.docEditDialog.instId = getNowDataTab().instId;
    state.docEditDialog.idxName = getNowDataTab().idxName;
    // 删除_id字段
    let obj = JSON.parse(src);
    state.docEditDialog._id = obj._id;
    delete obj._id;
    state.docEditDialog.doc = JSON.stringify(obj, null, 2);
    state.docEditDialog.visible = true;
};

const onEditSelectDoc = async (dt: any) => {
    if (dt.selectKeys.length > 1 || dt.selectKeys.length == 0) {
        ElMessage.warning(t('common.pleaseSelectOne'));
        return;
    }
    await onEditDoc(dt.selectKeys[0].src);
};

const onSwitchTrackTotal = async (dt: any) => {
    if (!dt.search.track_total_hits && dt.total === 10000) {
        dt.search.track_total_hits = true;
    } else {
        delete dt.search.track_total_hits;
    }
    if (dt.total >= 10000) {
        await fetchIndexData(); // 切换查询总数
    }
};

const onDeleteDocs = async (dt: any) => {
    let ids = dt.selectKeys.map((d: any) => d._id);
    // 二次确认后执行删除
    await useI18nDeleteConfirm(ids.join(', '));
    await doDeleteDoc(ids);
};

const doDeleteDoc = async (ids: any[]) => {
    let dataTab = getNowDataTab();
    await esApi.proxyReq('post', dataTab.instId, `/${dataTab.idxName}/_delete_by_query`, {
        query: { terms: { _id: ids } },
    });
    ElMessage.success(t('common.deleteSuccess'));
    await refreshIndex(); // 删除后刷新索引
    setTimeout(async () => {
        await fetchIndexData(); // 删除后刷新数据
    }, 500);
};
const onDownload = async (dt: any) => {
    let ids = dt.selectKeys.map((d: any) => d._id);
    console.log(ids);
};
const onIndexDetail = async (data: any) => {
    let param = {
        idxName: data.params.idxName,
        instId: data.params.instId,
    };
    esIndexDetailRef.value.open(param);
};
const onUpload = async (dt: any) => {
    let ids = dt.selectKeys.map((d: any) => d._id);
    console.log(ids);
};
const onReindex = async (instId: any, idxName: string) => {
    state.reIndexDialog.visible = true;
    // 弹出新增/修改索引窗口
    state.reIndexDialog.instId = instId;
    state.reIndexDialog.idxName = idxName;
    state.reIndexDialog.visible = true;
    let indices = await getIndicesByInstId(instId);
    state.reIndexDialog.idxNames = indices
        .map((x: any) => x.index)
        .filter((x: any) => x != idxName && x.indexOf('.') < 0)
        .sort();
    console.log(state.reIndexDialog);
};
const onBasicSearch = async (dt: any) => {
    dt.searchDialogVisible = true;
};

const onEsSearch = async (data: any) => {
    let dt = getNowDataTab();
    data.from = 0;
    data.size = dt.search.size;
    dt.search = data;

    await fetchIndexData();
    dt.searchDialogVisible = false;
};

const onCheckColumnFilter = (column: any) => {
    column.hidden = !column._show;
};

const onCheckAllColumns = (dt: any) => {
    dt.columns.forEach((c: any) => {
        if (c.key != '_table_index' && c.key != '_selected') {
            c._show = dt.checkAllColumns;
            c.hidden = !c._show;
        }
    });
};

const onFilterColumns = (dt: any) => {
    if (!dt.columnsFilterText) {
        dt.columns.forEach((c: any) => {
            if (c.key != '_table_index' && c.key != '_selected') {
                c._filterd = true;
            }
        });
    } else {
        dt.columns.forEach((c: any) => {
            if (c.key != '_table_index' && c.key != '_selected') {
                c._filterd = c.key.toLowerCase().indexOf(dt.columnsFilterText.toLowerCase()) > -1;
            }
        });
    }
};

const onSelectAll = async (dt: any) => {
    dt.datas.forEach((d: any) => (d._selected = dt.selectAll));
    if (!dt.selectAll) {
        dt.selectKeys = [];
    } else {
        dt.selectKeys = dt.datas;
    }
};

const onSelectRow = (dt: any, item: any) => {
    if (item._selected) {
        dt.selectKeys.push(item);
    } else {
        dt.selectKeys = dt.selectKeys.filter((d: any) => d._id != item._id);
    }
};

const onRefreshStats = async (dt: any) => {
    let stats = await esApi.proxyReq('get', dt.instId, `/${dt.idxName}/_stats`);
    dt.params.idx['docs.count'] = stats.indices[dt.idxName].primaries.docs.count;
    if (stats.indices[dt.idxName].health) {
        dt.params.idx.health = stats.indices[dt.idxName].health;
    }
    if (stats.indices[dt.idxName].status) {
        dt.params.idx.status = stats.indices[dt.idxName].status;
    }
};

const removeDataTab = (targetName: string) => {
    const tabNames = Object.keys(state.dataTabs);
    let activeName = state.activeName;
    tabNames.forEach((name, index) => {
        if (name === targetName) {
            const nextTab = tabNames[index + 1] || tabNames[index - 1];
            if (nextTab) {
                activeName = nextTab;
            }
        }
    });
    state.activeName = activeName;
    delete state.dataTabs[targetName];
};

const getNowDataTab = () => {
    return state.dataTabs[state.activeName];
};

const getHealthTagType = (health: string) => {
    return health == 'green' ? 'success' : health == 'yellow' ? 'warning' : 'danger';
};
</script>

<style lang="scss">
#es-op-tabs {
    .el-tabs {
        --el-tabs-header-height: 30px;
        .el-tabs__header {
            margin: 0 0 5px;
            .el-tabs__item {
                padding: 0 5px;
            }
        }
    }
}

.es-table-data {
    .es-table {
        border-left: var(--el-table-border);
        border-top: var(--el-table-border);
    }

    .es-table-column {
        padding: 0 2px;
        font-size: 12px;
        border-right: var(--el-table-border);
    }

    .header-column-title {
        height: 30px;
        display: flex;
        justify-content: center;
    }

    .table-data-cell {
        width: 100%;
        height: 100%;
        line-height: 30px;
        cursor: pointer;
    }

    .data-selection {
        background-color: var(--el-table-current-row-bg-color);
    }

    .update_field_active {
        background-color: var(--el-color-success-light-3);
    }

    .column-type {
        color: var(--el-color-info-light-3);
        font-weight: bold;
        position: absolute;
        top: -7px;
        padding: 2px;
    }

    .column-right {
        position: absolute;
        top: 2px;
        right: 0;
        padding: 2px;
    }
    .el-table-v2__overlay {
        z-index: 1;
    }
}

.el-drawer__header {
    padding: 0 15px !important;
    height: 50px;
    display: flex;
    align-items: center;
    margin-bottom: 0 !important;
    border-bottom: 1px solid var(--el-border-color);
}
</style>
